/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.event;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Predicate;

import org.springframework.context.ApplicationEvent;
import org.springframework.core.annotation.AliasFor;

/**
 将方法标记为应用程序事件侦听器的注释。
 如果带注释的方法支持单个事件类型，则该方法可以声明一个反映要侦听的事件类型的参数。
 如果带注释的方法支持多种事件类型，则该注释可能会使用classes属性引用一种或多种受支持的事件类型。
 有关更多详细信息，请参阅classes javadoc。
 事件可以是ApplicationEvent实例以及任意对象。
 @EventListener注释的处理是通过内部EventListenerMethodProcessor bean 执行的，该 bean 在使用 Java 配置时自动注册，
 或者在使用 XML 配置时通过<context:annotation-config/>或<context:component-scan/>元素手动注册。
 带注释的方法可能具有非void返回类型。 当他们这样做时，方法调用的结果作为一个新事件发送。 如果返回类型是数组或集合，
 则每个元素都作为一个新的单独事件发送。
 此注释可用作元注释以创建自定义组合注释。
 异常处理
 虽然事件侦听器可以声明它抛出任意异常类型，但从事件侦听器抛出的任何已检查异常都将被包装在UndeclaredThrowableException
 因为事件发布者只能处理运行时异常。
 异步侦听器
 如果您希望特定侦听器异步处理事件，则可以使用 Spring 的@Async支持，但在使用异步事件时请注意以下限制。
 如果异步事件侦听器抛出异常，则不会将其传播给调用者。 有关更多详细信息，请参阅AsyncUncaughtExceptionHandler 。
 异步事件侦听器方法无法通过返回值来发布后续事件。 如果您需要发布另一个事件作为处理结果，请注入ApplicationEventPublisher以手动发布事件。
 *
 * <h3>Ordering Listeners</h3>
 * <p>It is also possible to define the order in which listeners for a
 * certain event are to be invoked. To do so, add Spring's common
 * {@link org.springframework.core.annotation.Order @Order} annotation
 * alongside this event listener annotation.
 *
 * @author Stephane Nicoll
 * @author Sam Brannen
 * @since 4.2
 * @see EventListenerMethodProcessor
 * @see org.springframework.transaction.event.TransactionalEventListener
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EventListener {

	/**
	 * Alias for {@link #classes}.
	 */
	@AliasFor("classes")
	Class<?>[] value() default {};

	/**
	 * The event classes that this listener handles.
	 * <p>If this attribute is specified with a single value, the
	 * annotated method may optionally accept a single parameter.
	 * However, if this attribute is specified with multiple values,
	 * the annotated method must <em>not</em> declare any parameters.
	 */
	@AliasFor("value")
	Class<?>[] classes() default {};

	/**
	 * Spring Expression Language (SpEL) expression used for making the event
	 * handling conditional.
	 * <p>The event will be handled if the expression evaluates to boolean
	 * {@code true} or one of the following strings: {@code "true"}, {@code "on"},
	 * {@code "yes"}, or {@code "1"}.
	 * <p>The default expression is {@code ""}, meaning the event is always handled.
	 * <p>The SpEL expression will be evaluated against a dedicated context that
	 * provides the following metadata:
	 * <ul>
	 * <li>{@code #root.event} or {@code event} for references to the
	 * {@link ApplicationEvent}</li>
	 * <li>{@code #root.args} or {@code args} for references to the method
	 * arguments array</li>
	 * <li>Method arguments can be accessed by index. For example, the first
	 * argument can be accessed via {@code #root.args[0]}, {@code args[0]},
	 * {@code #a0}, or {@code #p0}.</li>
	 * <li>Method arguments can be accessed by name (with a preceding hash tag)
	 * if parameter names are available in the compiled byte code.</li>
	 * </ul>
	 */
	String condition() default "";

	/**
	 * An optional identifier for the listener, defaulting to the fully-qualified
	 * signature of the declaring method (e.g. "mypackage.MyClass.myMethod()").
	 * @since 5.3.5
	 * @see SmartApplicationListener#getListenerId()
	 * @see ApplicationEventMulticaster#removeApplicationListeners(Predicate)
	 */
	String id() default "";

}
